/*
  ==============================================================================

   Demonstration JuceAudioTemplateApp application in JUCE
   Copyright 2004 by Julian Storer.
   Modified 2008 by Martin Robinson

  ==============================================================================
*/

#include <iostream>
#include <juce/juce.h>
#include "MyTransportSource.h"

//==============================================================================
class AudioDemo  :  public Component,
					public ButtonListener,
					public ChangeListener,
					public AudioIODeviceCallback,
					public Timer
{
    //==============================================================================
    TextButton* audioSettingsButton;
	
    //==============================================================================
    // this wraps the actual audio device
    AudioDeviceManager audioDeviceManager;
	
    // this allows an audio source to be streamed to the IO device
    AudioSourcePlayer audioSourcePlayer;
	
	// this source is used to mix together the output from our synth source
    // and wave player source
    MixerAudioSource mixerSource;
	
	// the above objects are needed to manage the playback of audio
	// ...
	// we need one of each of the following objects to play a sound file
	
	/*
	String audioFilePath1;
	String audioFilePath2;
    // this controls the playback of a positionable audio stream, handling the
    // starting/stopping and sample-rate conversion
    AudioTransportSource transportSource1;
	AudioTransportSource transportSource2:
	 */
	
	OwnedArray<MyTransportSource> transportSources;
	
    // this is the actual stream that's going to read from the audio file.
//    AudioFormatReaderSource* currentAudioFileSource;
	
	
	
		
public:
	//==============================================================================
	AudioDemo()
    {
		setName (T("JuceAudioTemplateApp"));
		
		// zero our currentAudioFileSource for safety
		//currentAudioFileSource = 0;
		
		//==============================================================================
		
		addAndMakeVisible (audioSettingsButton = new TextButton (T("show audio settings..."),
																 T("click here to change the audio device settings")));
		audioSettingsButton->addButtonListener (this);

		
		//==============================================================================

		
		//transportSource2.addChangeListener(this);
		
		// and initialise the device manager with no settings so that it picks a
		// default device to use.
		const String error (audioDeviceManager.initialise (1, /* number of input channels */
														   2, /* number of output channels */
														   0, /* no XML settings.. */
														   true  /* select default device on failure */));
		
		if (error.isNotEmpty())
		{
			AlertWindow::showMessageBox (AlertWindow::WarningIcon,
										 T("JuceAudioTemplateApp"),
										 T("Couldn't open an output device!\n\n") + error);
		}
		else
		{
			String userDocumentsDir = File::getSpecialLocation(File::userDocumentsDirectory).getFullPathName();

			// set the audio file name (needs to be a valid path to an aif/wav on your system)
			// here we get the user documents folder first:
			
			File file("~/Desktop/");
			
			OwnedArray<File> results;
			
			file.findChildFiles(results, File::findFiles, false, T("*.aif"));
			file.findChildFiles(results, File::findFiles, false, T("*.wav"));
			
			
//			transportSources.add(new MyTransportSource(userDocumentsDir + String("/../Desktop/bong007.aif")));
//			transportSources.add(new MyTransportSource(userDocumentsDir + String("/../Desktop/bomb.wav")));
			
			// initialising the audioDeviceManager succeeded (no error)
			// register for start/stop messages from the transport source.. we need one for each audio file
			for (int i = 0; i < results.size() ; i++)
			{
				transportSources.add(new MyTransportSource(userDocumentsDir + String("/../Desktop/")+ results[i]->getFileName()));
				
				transportSources[i]->addChangeListener (this);
						
			// add the audio source to our mixer.. each of the AudioTransportSources need adding
				mixerSource.addInputSource (transportSources[i], false);
			
			}

			
			// ..and connect the mixer to our source player.
			audioSourcePlayer.setSource (&mixerSource);
			
			// start the IO device pulling its data from our callback..
			audioDeviceManager.setAudioCallback (this);
			
			
							
			
			// set the timer to pay our sound 1sec after the app launches
			// if the sound is started immediately the audio glitches
			startTimer(1000);
		}
	}
	
	~AudioDemo()
	{
		
		audioDeviceManager.setAudioCallback (0);
		
		audioSourcePlayer.setSource (0);
		
		deleteAllChildren();
	}
	
	//==============================================================================
	void audioDeviceIOCallback (const float** inputChannelData,
								int totalNumInputChannels,
								float** outputChannelData,
								int totalNumOutputChannels,
								int numSamples)
	{		
		// pass the audio callback on to our player source
		// you could do some processing on the sample data at this point
		// here we just pass it through unchanged
		audioSourcePlayer.audioDeviceIOCallback (inputChannelData, totalNumInputChannels, outputChannelData, totalNumOutputChannels, numSamples);
	}
	
	void audioDeviceAboutToStart (AudioIODevice* device)
	{
		audioSourcePlayer.audioDeviceAboutToStart (device);
	}
	
	void audioDeviceStopped()
	{
		audioSourcePlayer.audioDeviceStopped();
	}
	
	//==============================================================================
	void paint (Graphics& g)
	{
		// nothing here for now
	}
	
	void resized()
	{		
		audioSettingsButton->setBounds (10, 10, 200, 24);
		audioSettingsButton->changeWidthToFitText();
	}
	
	
	void buttonClicked (Button* button)
	{
		if (button == audioSettingsButton)
		{
			// Create an AudioDeviceSelectorComponent which contains the audio choice widgets...
			AudioDeviceSelectorComponent audioSettingsComp (audioDeviceManager,
															0, 1,
															2, 2,
															true,
															false,
															true,
															false);
			
			// ...and show it in a DialogWindow...
			audioSettingsComp.setSize (500, 400);
			
			DialogWindow::showModalDialog (T("Audio Settings"),
										   &audioSettingsComp,
										   this,
										   Colours::azure,
										   true);
		}
	}
		
	void changeListenerCallback (void* sender)
	{
		// callback from the transport source to tell us that play has
		// started or stopped
		
		// nothing to do here but you may want to know when a file has started or stopped 
		// e.g. to update the state of any buttons or to restart the file (one way of looping) or quit
		
		// you could for example, automatically quit the app when the file is finished
		// by uncommenting this line:
		//if(sender == &transportSource && !transportSource.isPlaying()) JUCEApplication::quit();

		// or to loop by uncommenting this line instead:
		//if(sender == &transportSource && !transportSource.isPlaying()) startTimer(0);
	}
	
	void timerCallback()
	{
		for(int i=0; i < transportSources.size(); i++)
		{
		// our timer callback - let's start the file playing back
		transportSources[i]->setPosition (0.0);
		transportSources[i]->start();
		}
		// don't repeatedly call the timer
		stopTimer();
	}
	
	
};


//==============================================================================
/** This is the top-level window that we'll pop up. Inside it, we'll create and
    show a AudioDemo component.
*/
class HelloWorldWindow  : public DocumentWindow
{
public:
    //==============================================================================
    HelloWorldWindow()
        : DocumentWindow (T("JuceAudioTemplateApp"),
                          Colours::lightgrey, 
                          DocumentWindow::allButtons, 
                          true)
    {
		setContentComponent (new AudioDemo());

        setVisible (true);
		setResizable(true,true);

        // centre the window on the desktop with this size
        centreWithSize (901, 450);
    }

    ~HelloWorldWindow()
    {
        // (the content component will be deleted automatically, so no need to do it here)
    }

    //==============================================================================
    void closeButtonPressed()
    {
        // When the user presses the close button, we'll tell the app to quit. This 
        // window will be deleted by the app object as it closes down.
        JUCEApplication::quit();
    }
};


//==============================================================================
/** This is the application object that is started up when Juce starts. It handles
    the initialisation and shutdown of the whole application.
*/
class JUCEHelloWorldApplication : public JUCEApplication
{
    /* Important! NEVER embed objects directly inside your JUCEApplication class! Use
       ONLY pointers to objects, which you should create during the initialise() method
       (NOT in the constructor!) and delete in the shutdown() method (NOT in the
       destructor!)

       This is because the application object gets created before Juce has been properly
       initialised, so any embedded objects would also get constructed too soon.
   */
    HelloWorldWindow* helloWorldWindow;

public:
    //==============================================================================
    JUCEHelloWorldApplication()
        : helloWorldWindow (0)
    {
        // NEVER do anything in here that could involve any Juce function being called
        // - leave all your startup tasks until the initialise() method.
    }

    ~JUCEHelloWorldApplication()
    {
        // Your shutdown() method should already have done all the things necessary to
        // clean up this app object, so you should never need to put anything in
        // the destructor.

        // Making any Juce calls in here could be very dangerous...
    }

    //==============================================================================
    void initialise (const String& commandLine)
    {
        // just create the main window...
        helloWorldWindow = new HelloWorldWindow();

        /*  ..and now return, which will fall into to the main event
            dispatch loop, and this will run until something calls
            JUCEAppliction::quit().

            In this case, JUCEAppliction::quit() will be called by the
            hello world window being clicked.
        */
    }

    void shutdown()
    {
        // clear up..

        if (helloWorldWindow != 0)
            delete helloWorldWindow;
    }

    //==============================================================================
    const String getApplicationName()
    {
        return T("JuceAudioTemplateApp");
    }

    const String getApplicationVersion()
    {
        return T("1.0");
    }

    bool moreThanOneInstanceAllowed()
    {
        return true;
    }

    void anotherInstanceStarted (const String& commandLine)
    {
    }
};


//==============================================================================
// This macro creates the application's main() function..
START_JUCE_APPLICATION (JUCEHelloWorldApplication)
